import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Rescaling, Conv2D, MaxPooling2D, Dense, Flatten, Dropout, BatchNormalization
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam
from sklearn.metrics import confusion_matrix, precision_score, recall_score, accuracy_score, f1_score
# location path of the datasets
train_dir = "/Users/preslav/Downloads/cw_cop528/imageset/train"
test_dir = "/Users/preslav/Downloads/cw_cop528/imageset/val"
# setting a common standard for the pixel values, to fall in
# setting a validation and training split
train_data = ImageDataGenerator(rescale=1./255,
validation_split=0.2)
val_data = ImageDataGenerator(rescale=1/255,
validation_split=0.2)
test_data = ImageDataGenerator(rescale=1./255)
# importing the data batches and setting their properties
train_batches = train_data.flow_from_directory(directory = train_dir,
target_size = (224, 224),
subset = "training",
batch_size = 32,
seed = 2)
validation_batches = val_data.flow_from_directory(directory = train_dir,
target_size = (224, 224),
subset = "validation",
batch_size = 32,
seed = 2)
test_batches = test_data.flow_from_directory(directory = test_dir,
target_size = (224, 224),
batch_size = 32,
shuffle = False)
Found 7578 images belonging to 10 classes. Found 1891 images belonging to 10 classes. Found 3925 images belonging to 10 classes.
# import of the class labels names and their total number
class_names = list(train_batches.class_indices.keys())
num_classes = len(class_names)
print(class_names)
print(num_classes)
['building', 'dog', 'fish', 'gas_station', 'golf', 'musician', 'parachute', 'radio', 'saw', 'vehicle'] 10
# import the test dataset, so that an unprocessed image can be taken from it for examination.
# further data is shuffled for the process taking place at the last section of this notebook
test_data_shuffled = tf.keras.utils.image_dataset_from_directory(test_dir, shuffle = True, seed = 247)
Found 3925 files belonging to 10 classes. Metal device set to: Apple M2
2023-03-17 11:04:00.835374: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support. 2023-03-17 11:04:00.835524: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)
def data_iterator(data):
'''
This function returns a batch,
given its provided with a dataset,
that has been devided into batches.
'''
iterator = data.as_numpy_iterator()
batch = iterator.next()
return batch
# get a batch from test_data_shuffled
example_batch = data_iterator(test_data_shuffled)
# get an image and its corresponding label from the batch
image, label = example_batch[0][18], example_batch[1][18]
# get the pixel value range
pixel_min = np.min(image)
pixel_max = np.max(image)
print("Pixel value range: [{}, {}]".format(pixel_min, pixel_max))
# plot the image and its respective actual label as title
plt.imshow(image.astype(np.uint8))
plt.title(class_names[label])
plt.colorbar()
plt.show()
2023-03-17 11:04:00.883582: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz
Pixel value range: [0.0, 255.0]
# importing a batch of images and labels
img, lbl = next(train_batches)
# plotting 9 images and their respective class labels
plt.figure(figsize = (12, 12))
for i in range(9):
class_index = np.argmax(lbl[i])
plt.subplot(3, 3, i + 1)
plt.imshow(img[i])
plt.title(class_names[class_index])
plt.axis("off")
plt.tight_layout()
plt.show()
# setting the model's architecture
model_base = Sequential([
Conv2D(16, (3,3), 1, activation = "relu"),
MaxPooling2D(),
Conv2D(32, (3,3), 1, activation = "relu"),
Conv2D(32, (3,3), 1, activation = "relu"),
MaxPooling2D(),
Conv2D(32, (3,3), 1, activation = "relu"),
Conv2D(32, (3,3), 1, activation = "relu"),
MaxPooling2D(),
Flatten(),
Dense(256, activation = "relu"),
Dense(num_classes, activation = "softmax")
])
# setting the model's loss function, gradient descnet optimizer and evaluation metrics
model_base.compile(optimizer = "adam", loss = "categorical_crossentropy", metrics = ["accuracy"])
# performing training of the model with the training batches and validation batches
epochs = 20
history_base= model_base.fit(train_batches,
validation_data = validation_batches,
epochs = epochs)
Epoch 1/20
2023-03-17 11:04:02.565846: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
237/237 [==============================] - ETA: 0s - loss: 1.8461 - accuracy: 0.3515
2023-03-17 11:04:20.855685: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
237/237 [==============================] - 22s 90ms/step - loss: 1.8461 - accuracy: 0.3515 - val_loss: 1.5436 - val_accuracy: 0.4966 Epoch 2/20 237/237 [==============================] - 21s 89ms/step - loss: 1.3036 - accuracy: 0.5645 - val_loss: 1.2939 - val_accuracy: 0.5828 Epoch 3/20 237/237 [==============================] - 21s 88ms/step - loss: 0.9802 - accuracy: 0.6767 - val_loss: 1.2480 - val_accuracy: 0.5970 Epoch 4/20 237/237 [==============================] - 21s 89ms/step - loss: 0.6295 - accuracy: 0.7928 - val_loss: 1.3356 - val_accuracy: 0.5902 Epoch 5/20 237/237 [==============================] - 21s 90ms/step - loss: 0.3028 - accuracy: 0.9000 - val_loss: 1.9532 - val_accuracy: 0.5643 Epoch 6/20 237/237 [==============================] - 21s 90ms/step - loss: 0.1449 - accuracy: 0.9512 - val_loss: 2.3566 - val_accuracy: 0.5595 Epoch 7/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0869 - accuracy: 0.9715 - val_loss: 2.4054 - val_accuracy: 0.5579 Epoch 8/20 237/237 [==============================] - 21s 90ms/step - loss: 0.0768 - accuracy: 0.9764 - val_loss: 2.6037 - val_accuracy: 0.5664 Epoch 9/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0456 - accuracy: 0.9854 - val_loss: 3.0778 - val_accuracy: 0.5420 Epoch 10/20 237/237 [==============================] - 22s 92ms/step - loss: 0.0559 - accuracy: 0.9826 - val_loss: 3.3298 - val_accuracy: 0.5510 Epoch 11/20 237/237 [==============================] - 21s 88ms/step - loss: 0.0505 - accuracy: 0.9840 - val_loss: 3.3499 - val_accuracy: 0.5457 Epoch 12/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0333 - accuracy: 0.9912 - val_loss: 3.5526 - val_accuracy: 0.5664 Epoch 13/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0418 - accuracy: 0.9875 - val_loss: 3.6053 - val_accuracy: 0.5579 Epoch 14/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0330 - accuracy: 0.9889 - val_loss: 3.6405 - val_accuracy: 0.5907 Epoch 15/20 237/237 [==============================] - 21s 90ms/step - loss: 0.0246 - accuracy: 0.9921 - val_loss: 3.9254 - val_accuracy: 0.5505 Epoch 16/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0621 - accuracy: 0.9805 - val_loss: 3.2867 - val_accuracy: 0.5553 Epoch 17/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0427 - accuracy: 0.9869 - val_loss: 3.4953 - val_accuracy: 0.5177 Epoch 18/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0506 - accuracy: 0.9836 - val_loss: 3.6244 - val_accuracy: 0.5547 Epoch 19/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0288 - accuracy: 0.9908 - val_loss: 3.7753 - val_accuracy: 0.5484 Epoch 20/20 237/237 [==============================] - 21s 89ms/step - loss: 0.0233 - accuracy: 0.9929 - val_loss: 4.1841 - val_accuracy: 0.5537
# getting the model's summary
model_base.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, None, None, 16) 448
max_pooling2d (MaxPooling2D (None, None, None, 16) 0
)
conv2d_1 (Conv2D) (None, None, None, 32) 4640
conv2d_2 (Conv2D) (None, None, None, 32) 9248
max_pooling2d_1 (MaxPooling (None, None, None, 32) 0
2D)
conv2d_3 (Conv2D) (None, None, None, 32) 9248
conv2d_4 (Conv2D) (None, None, None, 32) 9248
max_pooling2d_2 (MaxPooling (None, None, None, 32) 0
2D)
flatten (Flatten) (None, None) 0
dense (Dense) (None, 256) 4718848
dense_1 (Dense) (None, 10) 2570
=================================================================
Total params: 4,754,250
Trainable params: 4,754,250
Non-trainable params: 0
_________________________________________________________________
# Graphical evaluation of training and validaiton performance
acc = history_base.history['accuracy']
val_acc = history_base.history['val_accuracy']
loss = history_base.history['loss']
val_loss = history_base.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(11, 8))
plt.subplots_adjust(hspace = .3)
plt.subplot(2, 1, 1)
plt.plot(epochs_range, acc, label = 'Training Accuracy', color = "orange")
plt.plot(epochs_range, val_acc, label = 'Validation Accuracy', color = "blue")
plt.legend(loc = 'best')
plt.xlabel('Epochs')
plt.title('Training and Validation Accuracy', size = 13)
plt.subplot(2, 1, 2)
plt.plot(epochs_range, loss, label = 'Training Loss', color = "orange")
plt.plot(epochs_range, val_loss, label = 'Validation Loss', color = "blue")
plt.legend(loc = 'best')
plt.title('Training and Validation Loss', size = 13)
plt.xlabel('Epochs')
plt.suptitle("Base Model", size=15)
plt.show()
# test loss and accuracy measurments
test_loss, test_acc = model_base.evaluate(test_batches)
print('Test loss:', test_loss)
print('Test accuracy:', test_acc)
123/123 [==============================] - 7s 58ms/step - loss: 4.0784 - accuracy: 0.5605 Test loss: 4.078429222106934 Test accuracy: 0.5605095624923706
# getting prediction labales by running the softmax results in argmax
test_labels = test_batches.classes
y_pred = model_base.predict(test_batches)
predicted_lables = np.argmax(y_pred, axis = 1)
cm = confusion_matrix(test_labels, predicted_lables)
2/123 [..............................] - ETA: 6s
2023-03-17 11:11:14.851794: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
123/123 [==============================] - 7s 56ms/step
# dataframe containing the confussion matrix
cfm = pd.DataFrame(cm, index = class_names, columns = class_names)
# plotting the confussion matrix
sns.heatmap(cfm, annot=True, fmt='d', cmap='Purples')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.title('Base Model', size = 15)
plt.xticks(rotation=78)
plt.show()
print("Preicision score:", precision_score(test_labels, predicted_lables, average="weighted"))
print("Recall score:", recall_score(test_labels, predicted_lables, average = "weighted"))
print("F1_score:", f1_score(test_labels, predicted_lables, average = "weighted"))
Preicision score: 0.5672258136210193 Recall score: 0.5605095541401274 F1_score: 0.5593190906792165
# recall that at the start test_data_shuffles was introduced, it was shuffled
# so that displayed images are not ordered in the same way as in the dataset
# and variety of classes can be seen
def right_format_image(pic):
'''
This function returns a
reshaped image into 224x224
format in terms of height and
width.
Further it normalizes the
pixel values within the range
of [0, 1].
'''
img_size = (224, 224)
image = tf.image.resize(pic, img_size)
image_expanded = np.expand_dims(image, axis=0)
image_copy = np.copy(image_expanded)
normalized = image_copy/255.
return normalized
def data_iterator(data):
'''
This function returns as arrays the
components of a batch.
'''
iterator = data.as_numpy_iterator()
batch = iterator.next()
return batch
# plotting images from the test dataset, with their actual and predicted from the model labels
predicted_batch = data_iterator(test_data_shuffled)
plt.figure(figsize=(12, 12))
plt.subplots_adjust(wspace=.3)
plt.suptitle("Base Model", size = 20)
for i in range(9):
image, label = predicted_batch[0][i], predicted_batch[1][i]
predictions = model_base.predict(right_format_image(image))
prediction_label = class_names[predictions.argmax()]
ax = plt.subplot(3, 3, i + 1)
plt.imshow(image.astype(np.uint8))
plt.title("Actual label:{};\nPredicted label:{}".format(class_names[label],
class_names[predictions.argmax()]), size = 9)
plt.axis("off")
1/1 [==============================] - 0s 13ms/step 1/1 [==============================] - 0s 10ms/step 1/1 [==============================] - 0s 9ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 10ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 7ms/step 1/1 [==============================] - 0s 9ms/step